package cool.taomu.toolkit.template

import com.google.inject.Key
import com.google.inject.name.Names
import cool.taomu.toolkit.Context
import cool.taomu.toolkit.antlr4.template.engie.templateidentify.TempIdentifyParser.ContentContext
import cool.taomu.toolkit.antlr4.template.engie.templateidentify.TempIdentifyParser.DefineContext
import java.io.File
import java.io.StringWriter
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.util.Map
import java.util.Stack
import org.apache.commons.io.FileUtils
import org.slf4j.LoggerFactory

class ListenerInvocationHandler implements InvocationHandler {
    val static LOG = LoggerFactory.getLogger(ListenerInvocationHandler);

    val Object target;
    val Stack<String> type ;
    val StringWriter writer
    val Map<String, Object> DataModel

    Context context

    var mustacheKey = Key.get(ITemplate, Names.named("taomu.template.mustache"))
    var thymeleafKey = Key.get(ITemplate, Names.named("taomu.template.thymeleaf"))
    var velocityKey = Key.get(ITemplate, Names.named("taomu.template.velocity"))
    var freemarkerKey = Key.get(ITemplate, Names.named("taomu.template.freemarker"))
    var markdownKey = Key.get(ITemplate, Names.named("taomu.template.markdown"))
    var plantUmlKey = Key.get(ITemplate, Names.named("taomu.template.plantUml"))

    new(Object target, Context context, Stack<String> type, StringWriter writer, Map<String, Object> DataModel) {
        this.target = target;
        this.type = type;
        this.writer = writer;
        this.DataModel = DataModel
        this.context = context
    }

    override Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        var injector = context.injectorSupplier.get
        var String methodName = method.getName();
        if (methodName.startsWith("enter") || methodName.startsWith("exit")) {
            System.out.println("[拦截] 即将进入方法: " + methodName);
        }

        switch (methodName) {
            case "enterDefine": {
                var text = (args.get(0) as DefineContext).text.trim;
                println(text);
                type.push(text);
            }
            case "enterContent": {
                var text = (args.get(0) as ContentContext).text.trim;
                if (type.size > 0) {
                    var ttype = type.pop();
                    var file = File.createTempFile("template", ".temp")
                    FileUtils.writeStringToFile(file, text, "UTF-8");
                    switch (ttype) {
                        case "mustache": {
                            if (injector.getExistingBinding(mustacheKey) !== null) {
                                var c = injector.getInstance(mustacheKey).execute(file.absolutePath, DataModel);
                                writer.append(c.toString);
                            } else {
                                LOG.info("缺少 {} 插件", ttype)
                            }
                        }
                        case "thymeleaf": {
                            if (injector.getExistingBinding(thymeleafKey) !== null) {
                                var c = injector.getInstance(thymeleafKey).execute(file.absolutePath, DataModel);
                                writer.append(c.toString);
                            } else {
                                LOG.info("缺少 {} 插件", ttype)
                            }
                        }
                        case "velocity": {
                            if (injector.getExistingBinding(velocityKey) !== null) {
                                var c = injector.getInstance(velocityKey).execute(file.absolutePath, DataModel);
                                writer.append(c.toString);
                            } else {
                                LOG.info("缺少 {} 插件", ttype)
                            }
                        }
                        case "freemarker": {
                            if (injector.getExistingBinding(freemarkerKey) !== null) {
                                var c = injector.getInstance(freemarkerKey).execute(file.absolutePath, DataModel);
                                writer.append(c.toString);
                            } else {
                                LOG.info("缺少 {} 插件", ttype)
                            }
                        }
                        case "markdown": {
                            if (injector.getExistingBinding(markdownKey) !== null) {
                                var c = injector.getInstance(markdownKey).execute(file.absolutePath, DataModel);
                                writer.append(c.toString);
                            } else {
                                LOG.info("缺少 {} 插件", ttype)
                            }
                        }
                        case "plantUml": {
                            if (injector.getExistingBinding(plantUmlKey) !== null) {
                                var c = injector.getInstance(plantUmlKey).execute(file.absolutePath, DataModel);
                                writer.append(c.toString);
                            } else {
                                LOG.info("缺少 {} 插件", ttype)
                            }
                        }
                        default: {
                            writer.append(text);
                        }
                    }
                    writer.append("\n");
                }
            }
        }

        var Object result = null;
        if (target !== null) {
            result = method.invoke(target, args);
        }

        if (methodName.startsWith("enter") || methodName.startsWith("exit")) {
            System.out.println("[拦截] 已退出方法: " + methodName);
        }

        return result;
    }
}
